package com.zysc.processflow.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zysc.processflow.common.util.HttpUtils;
import com.zysc.processflow.common.util.StringUtils;
import com.zysc.processflow.entity.*;
import com.zysc.processflow.mapper.HandlerecordMapper;
import com.zysc.processflow.service.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class ProcessOperationServiceImpl implements IProcessOperationService  {

    @Autowired
    IHandleprocessnodeService handleprocessnodeService;
    @Autowired
    IHandlerecordcurrentnodeService handlerecordcurrentnodeService;

    @Autowired
    HandlerecordMapper handlerecordMapper;
    @Autowired
    IHandletaskService handletaskService;

    @Autowired
    IHandleprocesslineService handleprocesslineService;

    @Autowired
    ApplicationContext applicationContext;


    //递归调用,有节点需要推动的时候执行一次
    //目前有四处调用这里
    //1.报警流程初始化后,会推动'开始节点',往后推一次
    //2.用户处置时,会推动'处置节点',往后推一次
    @Override
    public Boolean pushNode(Handlerecord handlerecord, String nodeid){
        boolean b1 = true;
        boolean b2 = true;
        boolean b3 = true;
        boolean b4 = true;
        //1.获取这个节点的后边的节点,如果没有,把这个节点状态改为block(阻塞),返回的都是没阻塞的
        List<Handleprocessnode> nextNodeList = this.getCanNextNodeAndUpdateCannotNextNodeStatus(handlerecord.getId(),nodeid,true);
        //2.遍历后面的节点
        for (Handleprocessnode nextnode : nextNodeList) {
            if (StringUtils.equalsAndNotNull(nextnode.getNodetype(), "处置节点")) {
                //1.旧节点在活动节点表的状态改为"overdue",新节点的状态改为"active"
                b1 = this.updateCurrentnodeStatus(handlerecord.getId(), nodeid, "overdue");
                b2 = this.updateCurrentnodeStatus(handlerecord.getId(), nextnode.getId(), "active");
                //2.删除旧节点的任务
                b3 = handletaskService.removeOldTask(handlerecord.getId(), nodeid);
                //3.新增新节点的任务
                b4 = handletaskService.saveNodeTaskByRecordAndNextNode(handlerecord, nextnode);
            } else if (StringUtils.equalsAndNotNull(nextnode.getNodetype(), "逻辑或节点")) {
                //1.旧节点在活动节点表的状态改为"overdue",新节点的状态改为"active"
                b1 = this.updateCurrentnodeStatus(handlerecord.getId(), nodeid, "overdue");
                b2 = this.updateCurrentnodeStatus(handlerecord.getId(), nextnode.getId(), "active");
                //2.查看后边的条件是不是可以走通
                boolean canNext1 = false;
                List<Handleprocessline> nextLineByNodeId = this.getNextLineByNodeId(nextnode.getId());
                for (Handleprocessline line : nextLineByNodeId) {//一般只有一个,虽然是for循环
                    if (this.getNodeConditionResult(line, handlerecord.getId())) {//这里判断线上de条件
                        canNext1 = true;
                    }
                }
                //3.,如果可以走通,那么删除该逻辑或节点之前的所有任务,如果不能走通,那就不能删,不能继续推
                if (canNext1) {
                    //删除全部旧节点的任务
                    List<Handlerecordcurrentnode> allPriorNodeList = this.getAllPriorNodeList(handlerecord.getId(), nextnode.getId());
                    List<String> allPriorNodeIdList = allPriorNodeList.stream().map(node -> node.getCurrentnodeid()).collect(Collectors.toList());
                    b3 = handletaskService.removeOldTaskByNodeList(handlerecord.getId(), allPriorNodeIdList);
                    //在推一次
                    b4 = this.pushNode(handlerecord, nextnode.getId());
                }
            } else if (StringUtils.equalsAndNotNull(nextnode.getNodetype(), "逻辑与节点")) {
                //1.旧在活动节点表的状态改为"overdue",新节点的状态改为"active"
                b1 = this.updateCurrentnodeStatus(handlerecord.getId(), nodeid, "overdue");
                b2 = this.updateCurrentnodeStatus(handlerecord.getId(), nextnode.getId(), "active");
                //2.查找该节点之前的节点的状态
                List<Handlerecordcurrentnode> priorNodeList = this.getPriorNodeList(handlerecord.getId(), nextnode.getId());
                //3.判断之前的节点状态是不是都完成了
                boolean priorNodeFinished = true;
                if (priorNodeList.stream().filter(node -> node.getState() == null || !node.getState().equals("overdue")).collect(Collectors.toList()).size() > 0) {
                    priorNodeFinished = false;
                }
                //4.前边的条件满足了再走下边逻辑
                if (priorNodeFinished) {
                    //5.判断后边的线能不能走通
                    List<Handleprocessline> nextLineByNodeId = this.getNextLineByNodeId(nextnode.getId());
                    boolean canNext = false;
                    for (Handleprocessline line : nextLineByNodeId) {
                        if (this.getNodeConditionResult(line, handlerecord.getId())) {//这里判断线上de条件
                            canNext = true;
                        }
                    }
                    //6.如果能走通
                    if (canNext) {
                        //删除全部旧节点的任务
                        List<Handlerecordcurrentnode> allPriorNodeList = this.getAllPriorNodeList(handlerecord.getId(), nextnode.getId());
                        List<String> allPriorNodeIdList = allPriorNodeList.stream().map(node -> node.getCurrentnodeid()).collect(Collectors.toList());
                        b3 = handletaskService.removeOldTaskByNodeList(handlerecord.getId(), allPriorNodeIdList);
                        //在推一次
                        b4 = this.pushNode(handlerecord, nextnode.getId());
                    }
                }
            } else if (StringUtils.equalsAndNotNull(nextnode.getNodetype(), "结束节点")) {
                Long tm = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
                //1.firstnod在活动节点表的状态改为"overdue",新节点的状态改为"overdue"
                b1 = this.updateCurrentnodeStatus(handlerecord.getId(), nodeid, "overdue");
                b2 = this.updateCurrentnodeStatus(handlerecord.getId(), nextnode.getId(), "overdue");
                //2.删除全部任务
                b3 = handletaskService.removeHandelAndUrgeTaskByRecordId(handlerecord.getId());
                //3.record表的status改为1
                Handlerecord temp = new Handlerecord();
                temp.setId(handlerecord.getId());
                temp.setHandlestatus("1");
                temp.setEndtime(tm);
                int updatenum = handlerecordMapper.updateById(temp);
                b4 = updatenum>0;
                //4.删除所有current节点
                this.removeAllCurrentNodeByRecordId(handlerecord.getId());
            }
        }
        return b1&&b2&&b3&&b4;
    }

    //推动阻塞的节点往前一次
    @Override
    public boolean pushBlockNodeByReason(Handlerecord record, String blockreason) {
        boolean result = true;
        LambdaQueryWrapper<Handlerecordcurrentnode> currentnodeQW  = new LambdaQueryWrapper<>();
        currentnodeQW.eq(Handlerecordcurrentnode::getRecordid,record.getId())
                .eq(Handlerecordcurrentnode::getState,"block")
                .eq(Handlerecordcurrentnode::getBlockreason,blockreason);
        List<Handlerecordcurrentnode> handlerecordcurrentnodeList = handlerecordcurrentnodeService.list(currentnodeQW);
        for (Handlerecordcurrentnode node : handlerecordcurrentnodeList) {
            boolean b = this.pushNode(record, node.getCurrentnodeid());
            if (!b) {
                result = false;
            }
        }
        return result;
    }

    //根据流程,获得该流程第一个节点
    @Override
    public Handleprocessnode getFirstNodeByProcess(Handleprocess process) {
        LambdaQueryWrapper<Handleprocessnode> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(Handleprocessnode::getProcessid,process.getId())
                .eq(Handleprocessnode::getIsfirstnode,"1");
        List<Handleprocessnode> list = handleprocessnodeService.list(queryWrapper);
        if(list.size()>0){
            return list.get(0);
        }
        return null;
    }

    //获取下一个节点
    @Override
    public Handleprocessnode getNextNode(String nodeid) {
        LambdaQueryWrapper<Handleprocessnode> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(Handleprocessnode::getPriornodeid,nodeid);
        List<Handleprocessnode> list = handleprocessnodeService.list(queryWrapper);
        if(list.size()>0){
            return list.get(0);
        }
        return null;
    }

    //获取下一个节点,根据线
    @Override
    public List<Handleprocessline> getNextLineByNodeId(String nodeid) {
        LambdaQueryWrapper<Handleprocessline> lineqw =  new LambdaQueryWrapper<>();
        lineqw.eq(Handleprocessline::getSourcenodeid,nodeid);
        List<Handleprocessline> handleprocesslineList = handleprocesslineService.list(lineqw);
        return handleprocesslineList;
    }

    //获取下一个节点根据,根据nodeid
    @Override
    public List<Handleprocessnode> getNextNodeByNodeId(String nodeid, Boolean thinkingOfConditionOnLine) {
        List<Handleprocessline> nextLineByNodeId = this.getNextLineByNodeId(nodeid);
        List<Handleprocessnode> result = new ArrayList<>();
        nextLineByNodeId.forEach(line->{
            String targetnodeid = line.getTargetnodeid();
            Handleprocessnode handleprocessnode = handleprocessnodeService.getById(targetnodeid);
            if(thinkingOfConditionOnLine){//这里应该改成condition的条件
                if (true){//这里以后要改成线上的判断条件
                    result.add(handleprocessnode);
                }else{

                }
            }else{
                result.add(handleprocessnode);
            }
        });
        return result;
    }

    //根据节点id , 获取前一个节点
    @Override
    public List<Handleprocessnode> getPriorNodeByNodeId(String nodeid) {
        LambdaQueryWrapper<Handleprocessline> lineqw =  new LambdaQueryWrapper<>();
        lineqw.eq(Handleprocessline::getTargetnodeid,nodeid);
        List<Handleprocessline> handleprocesslineList = handleprocesslineService.list(lineqw);
        List<Handleprocessnode> result = new ArrayList<>();
        for (Handleprocessline handleprocessline : handleprocesslineList) {
            Handleprocessnode handleprocessnode = handleprocessnodeService.getById(handleprocessline.getSourcenodeid());
            result.add(handleprocessnode);
        }
        return result;
    }

    // 更新current节点的状态
    @Override
    public Boolean updateCurrentnodeStatus(String recordid, String nodeid, String newStatus) {
        List<Handlerecordcurrentnode> list = new ArrayList<>();
        LambdaQueryWrapper<Handlerecordcurrentnode> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(Handlerecordcurrentnode::getRecordid,recordid)
                .eq(Handlerecordcurrentnode::getCurrentnodeid,nodeid);
        list = handlerecordcurrentnodeService.list(queryWrapper);
        Boolean result = true;
        for (Handlerecordcurrentnode item : list) {
            Handlerecordcurrentnode temp = new Handlerecordcurrentnode();
            temp.setId(item.getId());
            temp.setState(newStatus);
            boolean b = handlerecordcurrentnodeService.saveOrUpdate(temp);
            if (!b) {
                result = false;
            }
        }
        return result;
    }
    //获取下一个节点,并且将不能通的下一个节点更改其状态
    @Override
    public List<Handleprocessnode> getCanNextNodeAndUpdateCannotNextNodeStatus(String recordid, String nodeid, Boolean thinkingOfConditionOnLine) {
        List<Handleprocessnode> result = new ArrayList<>();//后边的节点
        //1.取到线
        List<Handleprocessline> nextLineByNodeId = this.getNextLineByNodeId(nodeid);
        //2.遍历线
        Boolean blockFlag = false;
        for (Handleprocessline line : nextLineByNodeId) {
            String targetnodeid = line.getTargetnodeid();
            Handleprocessnode handleprocessnode = handleprocessnodeService.getById(targetnodeid);
            if (thinkingOfConditionOnLine) {//这里应该改成condition的条件
                if (this.getNodeConditionResult(line,recordid)) {//这里有拦截逻辑 , 返回true和false ,true允许通行, false不允许通行
                    result.add(handleprocessnode);
                } else {
                    blockFlag = true;
                }
            } else {
                result.add(handleprocessnode);
            }
        }
        if((result==null || result.size()==0)&&blockFlag){//有被线的阻塞了,导致result的数量是0才算block
            this.updateCurrentnodeStatus(recordid,nodeid,"block");
        }
        return result;
    }

    //判断线是不是阻塞,反射执行线上的条件方法
    @Override
    public Boolean getNodeConditionResult(Handleprocessline line, String recordid){
        String conditiontype = line.getConditiontype();
        String methodContent = line.getConditionvalue();
        if(StringUtils.isNull(methodContent)){
            return true;
        }
        //判断线的类型
        if(StringUtils.equalsAndNotNull(conditiontype,"接口")){//如果是接口,这里需要接口返回一个true或者false
            Handlerecord handlerecord = handlerecordMapper.selectById(recordid);
            String ywxtid = handlerecord.getYwxtid();
            Map map = new HashMap();
            map.put("recordid",recordid);
            map.put("ywxtid",ywxtid);
            map.put("line",line);
            try{
                String res = HttpUtils.doPostJson(methodContent, JSON.toJSONString(map));
                JSONObject jsonObject = JSON.parseObject(res);
                Map result = (Map)jsonObject;
                if((Integer) result.getOrDefault("code",500)==200){
                    return (Boolean) result.getOrDefault("data",false);
                }else{
                    //1.拿到返回的原因,作为前一个结点阻塞的原因
                    String blockReason = (String) result.getOrDefault("message", "");
                    LambdaQueryWrapper<Handlerecordcurrentnode> currentNodeQw = new LambdaQueryWrapper<>();
                    currentNodeQw.eq(Handlerecordcurrentnode::getRecordid,recordid)
                            .eq(Handlerecordcurrentnode::getCurrentnodeid,line.getSourcenodeid());
                    List<Handlerecordcurrentnode> handlerecordcurrentnodeList = handlerecordcurrentnodeService.list(currentNodeQw);
                    if(handlerecordcurrentnodeList.size()>0){
                        String currentnodeid = handlerecordcurrentnodeList.get(0).getId();
                        Handlerecordcurrentnode handlerecordcurrentnode = new Handlerecordcurrentnode();
                        handlerecordcurrentnode.setId(currentnodeid);
                        handlerecordcurrentnode.setState("block");
                        handlerecordcurrentnode.setBlockreason(blockReason);
                        handlerecordcurrentnodeService.saveOrUpdate(handlerecordcurrentnode);
                    }
                    return false;
                }
            }catch(Exception e){
                e.printStackTrace();
                return false;
            }
        }else{//默认是反射
            try{
                //通过反射,执行方法,拿到方法返回值(布尔,存到数据库的方法要求参数是recordid,返回布尔值,其他逻辑随意)
                int lastPointIndex = methodContent.lastIndexOf(".");
                String classFullName = methodContent.substring(0, lastPointIndex);
                String method = methodContent.substring(lastPointIndex+1);
                Class clazz = Class.forName(classFullName);
                Object tarObject = clazz.newInstance();
                Method tarMethod = clazz.getMethod(method,ApplicationContext.class,Handleprocessline.class,String.class);
                Map invokeResult = (Map) tarMethod.invoke(tarObject, applicationContext, line, recordid);

                if((Boolean) invokeResult.getOrDefault("data",false)){
                    return true;
                }else{
                    //1.拿到返回的原因,作为前一个结点阻塞的原因
                    String blockReason = (String) invokeResult.getOrDefault("message", "");
                    LambdaQueryWrapper<Handlerecordcurrentnode> currentNodeQw = new LambdaQueryWrapper<>();
                    currentNodeQw.eq(Handlerecordcurrentnode::getRecordid,recordid)
                            .eq(Handlerecordcurrentnode::getCurrentnodeid,line.getSourcenodeid());
                    List<Handlerecordcurrentnode> handlerecordcurrentnodeList = handlerecordcurrentnodeService.list(currentNodeQw);
                    if(handlerecordcurrentnodeList.size()>0){
                        String currentnodeid = handlerecordcurrentnodeList.get(0).getId();
                        Handlerecordcurrentnode handlerecordcurrentnode = new Handlerecordcurrentnode();
                        handlerecordcurrentnode.setId(currentnodeid);
                        handlerecordcurrentnode.setState("block");
                        handlerecordcurrentnode.setBlockreason(blockReason);
                        handlerecordcurrentnodeService.saveOrUpdate(handlerecordcurrentnode);
                    }
                    return false;
                }
            }catch(Exception e){
                return false;
            }
        }
    }

    //获取这个节点之前的current节点
    @Override
    public List<Handlerecordcurrentnode> getPriorNodeList(String recordid, String nodeid) {
        List<Handleprocessnode> priorNode = this.getPriorNodeByNodeId(nodeid);
        Set priorNodeIdSet = new HashSet();
        priorNode.stream().forEach(node->{
            priorNodeIdSet.add(node.getId());
        });
        if(priorNodeIdSet.size()==0){
            return new ArrayList<>();
        }
        LambdaQueryWrapper<Handlerecordcurrentnode> qw =new LambdaQueryWrapper<>();
        qw.eq(Handlerecordcurrentnode::getRecordid,recordid).in(Handlerecordcurrentnode::getCurrentnodeid,priorNodeIdSet);
        List<Handlerecordcurrentnode> handlerecordcurrentnodeList = handlerecordcurrentnodeService.list(qw);
        return handlerecordcurrentnodeList;
    }

    //或者这个节点之前的全部current节点
    @Override
    public List<Handlerecordcurrentnode> getAllPriorNodeList(String recordid, String nodeid) {
        List<Handlerecordcurrentnode> result = new ArrayList<>();
        List<Handlerecordcurrentnode> priorNodeList = this.getPriorNodeListRecursion(recordid, nodeid,result);
        return priorNodeList;
    }

    //删除某流程的全部current节点
    @Override
    public boolean removeAllCurrentNodeByRecordId(String recordid) {
        LambdaQueryWrapper<Handlerecordcurrentnode> currentCodeQW = new LambdaQueryWrapper<>();
        currentCodeQW.eq(Handlerecordcurrentnode::getRecordid,recordid);
        return handlerecordcurrentnodeService.remove(currentCodeQW);
    }


    public List<Handlerecordcurrentnode> getPriorNodeListRecursion(String recordid, String nodeid, List<Handlerecordcurrentnode> result) {
        List<Handlerecordcurrentnode> priorNodeList = this.getPriorNodeList(recordid, nodeid);
        priorNodeList.stream().forEach(node->{
            if(!result.contains(node)){
                result.add(node);
            }
            List<Handlerecordcurrentnode> priorNodeList1 = this.getPriorNodeListRecursion(recordid, node.getCurrentnodeid(),result);
        });
        return result;
    }
}
